#include "expressiontest.h"
#include "core/expression.h"

typedef QMap<QString, QStringList> Dictionary;

ExpressionTest::ExpressionTest(QObject *parent) :
  QObject(parent),
  expression(nullptr)
  {
  }

void ExpressionTest::initTestCase()
  {
  expression = new Expression();
  }

void ExpressionTest::testMultiplication_data()
  {  
  QTest::addColumn<QString>("leftFactor");
  QTest::addColumn<QString>("rightFactor");
  QTest::addColumn<QString>("product");
  
  QTest::newRow("1") << "delta(x,y)" << "a_z" << "delta(x,y) a_z";
  QTest::newRow("2") << "delta(x,y) - b_y a_x" << "a_z" << "delta(x,y) a_z - b_y a_x a_z";
  QTest::newRow("3") << "delta(x,y) - b_y a_x + a_x" << "a_z" << "delta(x,y) a_z - b_y a_x a_z + a_x a_z";
  QTest::newRow("4") << "a_i" << "a_i  + b_x" << "a_i a_i + a_i b_x";
  QTest::newRow("5") << "a_i + b_x" << "a_i" << "a_i a_i + b_x a_i";
  QTest::newRow("6") << "a_i + b_x" << "c_y + d_z" << "a_i c_y + b_x c_y + a_i d_z + b_x d_z";
  QTest::newRow("7") << "2 a_i + 3 b_x" << "5 c_y - 7 d_z" << "10 a_i c_y + 15 b_x c_y - 14 a_i d_z - 21 b_x d_z";
  }

void ExpressionTest::testMultiplication()
  {
  QFETCH(QString, leftFactor);
  QFETCH(QString, rightFactor);
  QFETCH(QString, product);

  translator.stringToExp(leftFactor, *expression);
  Expression factor;
  translator.stringToExp(rightFactor, factor);

  Expression eResult;
  expression->multiplyWith(&factor, eResult);

  QString originalExpression = translator.expToString(*expression);
  QString result = translator.expToString(eResult);
  QCOMPARE(originalExpression, leftFactor);
  QCOMPARE(result, product);
  }

void ExpressionTest::testSort_data()
  {
  QTest::addColumn<QString>("input");
  QTest::addColumn<QString>("output");
  QTest::newRow("1") << "b delta(x,y) a delta(x,y) c" << "a b c delta(x,y) delta(x,y)";
  QTest::newRow("2") << "a delta(a,b) fun(i,j) a_i + a_i" << "a delta(a,b) fun(i,j) a_i + a_i";
  QTest::newRow("3") << "a delta(a,b) fun(i,j) a_i + a_i a_j a_k a_l a_m" << "a_i a_j a_k a_l a_m + a delta(a,b) fun(i,j) a_i";
  }

void ExpressionTest::testSort()
  {
  QFETCH(QString, input);
  QFETCH(QString, output);
  translator.stringToExp(input, *expression);
  expression->sort();
  QString result = translator.expToString(*expression);
  QCOMPARE(result, output);
  }

void ExpressionTest::testFactorOutCommonSentence_data()
  {
  QTest::addColumn<QString>("input");
  QTest::addColumn<QString>("output");  
  QTest::addColumn<bool>("changed");
  QTest::newRow("1") << "b delta(x,y) + delta(x,y) a c" << "delta(x,y) (b + a c)" << true;
  QTest::newRow("2") << "(1 + delta(i,j) f_i g(x,y) - x z delta(k,l) f(i) g(x,y)) a_i" <<
                        "(1 + delta(i,j) f(i) g(x,y) - x z delta(k,l) f(i) g(x,y)) a_i" << false;
  QTest::newRow("3") << "(1) a_i" << "(1) a_i" << false;
  QTest::newRow("4") << "delta(x,y) a_z - b_y a_x a_z" << "delta(x,y) a_z - b_y a_x a_z" << false;
  }

void ExpressionTest::testFactorOutCommonSentence()
  {
  QFETCH(QString, input);
  QFETCH(QString, output);
  QFETCH(bool, changed);
  translator.stringToExp(input, *expression);
  bool resChanged = expression->factorOutCommonSentence();
  QString result = translator.expToString(*expression);
  QCOMPARE(result, output);
  QCOMPARE(resChanged, changed);
  }

void ExpressionTest::testFactorOutType_data()
  {
  QTest::addColumn<QString>("input");
  QTest::addColumn<QString>("output");
  QTest::addColumn<bool>("changed");
  QTest::addColumn<Word::Type>("type");
  QTest::newRow("1") << "a b + a b c_i" << "a b (1 + c_i)" << true << Word::WT_VARIABLE;
  QTest::newRow("2") << "a b + d + a b c_i" << "a b (1 + c_i) + d" << true << Word::WT_VARIABLE;
  QTest::newRow("3") << "a b + a b c_i + d e + a b d_e" << "a b (1 + c_i + d_e) + d e" << true << Word::WT_VARIABLE;
  QTest::newRow("4") << "a b + a f(i)" << "a b + a f(i)" << false << Word::WT_VARIABLE;
  QTest::newRow("5") << "(1 + delta(i,j) f_i g(x,y) - x z delta(k,l) f(i) g(x,y) ) a_i" <<
                        "(f(i) g(x,y) (delta(i,j) - x z delta(k,l)) + 1) a_i" << true << Word::WT_FUNCTION;
  }

void ExpressionTest::testFactorOutType()
  {
  QFETCH(QString, input);
  QFETCH(QString, output);
  QFETCH(bool, changed);
  QFETCH(Word::Type, type);
  translator.stringToExp(input, *expression);
  bool resChanged = expression->factorOutType(type);
  QString result = translator.expToString(*expression);
  QCOMPARE(result, output);
  QCOMPARE(resChanged, changed);
  }

void ExpressionTest::testFactorOutWhatYouCan_data()
  {
  QTest::addColumn<QString>("input");
  QTest::addColumn<QString>("output");
  QTest::newRow("1") << "1 + 2 a_i b_k + 4 f_i a_i b_k " << "2 a_i b_k (1 + 2 f(i)) + 1";
  QTest::newRow("2") << "1 + delta(i,j) f_i g(x,y) - x z delta(k,l) f(i) g(x,y)" <<
                        "f(i) g(x,y) (delta(i,j) - x z delta(k,l)) + 1";
  QTest::newRow("3") << "(1 + delta(i,j) f_i g(x,y) - x z delta(k,l) f(i) g(x,y)) a_i" <<
                        "(f(i) g(x,y) (delta(i,j) - x z delta(k,l)) + 1) a_i";
  QTest::newRow("4") << "-b_x a_y delta(m,n) - a_z delta(m,n) " << "-delta(m,n) (b_x a_y + a_z)";
  }

void ExpressionTest::testFactorOutWhatYouCan()
  {
  QFETCH(QString, input);
  QFETCH(QString, output);
  translator.stringToExp(input, *expression);
  expression->factorOutWhatYouCan();
  QString result = translator.expToString(*expression);
  QCOMPARE(result, output);
  }


void ExpressionTest::testApplyLabelDictionary_data()
  {
  QTest::addColumn<QString>("input");
  QTest::addColumn<QString>("output");
  QTest::addColumn<Dictionary>("dict");

    {
    Dictionary dict;
    dict.insert("%1", QStringList("i"));
    dict.insert("%2", QStringList("j"));
    QTest::newRow("1") << "a_%1 a_%2" << "a_i a_j" << dict;
    }

    {
    Dictionary dict;
    dict.insert("%1", QStringList("x"));
    dict.insert("%2", QStringList("y"));
    dict.insert("%3", QStringList("z"));
    QTest::newRow("2") << "(delta(%1,%2) - b_%2 a_%1) a_%3" << "(delta(x,y) - b_y a_x) a_z" << dict;
    }

    {
    Dictionary dict;
    dict.insert("%1", QStringList("i"));
    dict.insert("%2", QStringList("j"));
    QTest::newRow("3") << "-b_%2 a_%1 + delta(%1,%2)" << "-b_j a_i + delta(i,j)" << dict;
    }
  }

void ExpressionTest::testApplyLabelDictionary()
  {
  QFETCH(QString, input);
  QFETCH(QString, output);
  QFETCH(Dictionary, dict);
  translator.stringToExp(input, *expression);
  expression->applyLabelDictionary(dict);
  QString result = translator.expToString(*expression);
  QCOMPARE(result, output);
  }

void ExpressionTest::cleanupTestCase()
  {
  delete expression;
  }
